package io.singulart.particle_progress_bar;

import ohos.agp.components.Attr;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ParticleProgressBar extends Component implements Component.DrawTask {
    private EventHandler mHandler = new EventHandler(EventRunner.getMainEventRunner());
    private float BALL_SIZE = 10;
    private int BALLS_COUNT = 8;

    private List<Ball> mBalls;

    private int mStartScale = BALLS_COUNT;
    private int mColor;

    private boolean mEnabled;

    public ParticleProgressBar(Context context) {
        this(context, null);
    }

    public ParticleProgressBar(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public ParticleProgressBar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initAttrSet(attrSet);
    }

    private void initAttrSet(AttrSet attrSet) {
        if (attrSet == null) {
            return;
        }
        mEnabled = getBoolean(attrSet, "ppb_enabled", false);
        BALLS_COUNT = getInt(attrSet, "ppb_count_balls", 8);
        mColor = getAttrSetColor(attrSet, "ppb_color", Color.WHITE);
        mStartScale = BALLS_COUNT;
        if (mEnabled) {
            showProgress();
        }
    }

    private void init() {
        addDrawTask(this);
        createBalls();
    }

    /**
     * set progress ball count
     *
     * @param count int
     */
    public void setProgressCountBalls(int count) {
        BALLS_COUNT = count;
        mStartScale = BALLS_COUNT;
    }

    /**
     * set progress color
     *
     * @param color int
     */
    public void setProgressColor(int color) {
        this.mColor = color;
    }

    /**
     * show progress
     */
    public void showProgress() {
        this.mEnabled = true;
        init();
        initBallPositionChanged();
        mHandler.postTask(this::invalidate);
    }

    /**
     * progress dismiss
     */
    public void disMissProgress() {
        this.mEnabled = false;
        invalidate();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!mEnabled) {
            return;
        }
        for (Ball ball : mBalls) {
            ball.render(canvas);
        }

        instantiateBalls();
    }

    private void instantiateBalls() {
        if (mStartScale == mBalls.size()) {
            mStartScale = 0;
        }

        for (int i = 0; i < mBalls.size(); i++) {
            Ball ball = mBalls.get(i);
            if (mStartScale == i) {
                ball.setSize(BALL_SIZE);
            } else {
                if (ball.getSize() > 0.5F) {
                    ball.setSize(ball.getSize() * 0.89F);
                }
            }
        }

        mStartScale++;

        mHandler.postTask(this::invalidate, (900 / (BALLS_COUNT * 2)));
    }

    private void initBallPositionChanged() {
        if (mBalls != null) {
            for (int i = 0; i < mBalls.size(); i++) {
                double centerViewW = getWidth() / 2F;
                double centerViewH = getHeight() / 2F;
                double radius = centerViewW * 0.5;

                Ball ball = mBalls.get(i);
                BALL_SIZE = (float) ((2F * Math.PI * radius) / BALLS_COUNT / 3F);
                ball.setSize((float) (BALL_SIZE * 0.8));

                double x = (radius * Math.cos(Math.toRadians(ball.getAngle()))) + centerViewW;
                double y = (radius * Math.sin(Math.toRadians(ball.getAngle()))) + centerViewH;
                ball.setPosition(x, y);
            }
        }
    }

    private void createBalls() {
        mBalls = new ArrayList<>();
        for (int i = 0; i < BALLS_COUNT; i++) {
            mBalls.add(new Ball(BALL_SIZE, mColor, (360F / BALLS_COUNT) * i));
        }
    }

    private boolean getBoolean(AttrSet attrSet, String attrName, boolean defaultValue) {
        if (attrSet == null || attrName == null || attrName.isEmpty()) {
            return defaultValue;
        }
        Optional<Attr> attrOptional = attrSet.getAttr(attrName);
        if (attrOptional == null || !attrOptional.isPresent()) {
            return defaultValue;
        }
        return attrOptional.get().getBoolValue();
    }

    private int getInt(AttrSet attrSet, String attrName, int defaultInt) {
        if (attrSet == null || attrName == null || attrName.isEmpty()) {
            return defaultInt;
        }
        Optional<Attr> attrOptional = attrSet.getAttr(attrName);
        if (attrOptional == null || !attrOptional.isPresent()) {
            return defaultInt;
        }
        return attrOptional.get().getIntegerValue();
    }

    private int getAttrSetColor(AttrSet attrSet, String attrName, Color defaultColor) {
        if (attrSet == null || attrName == null || attrName.isEmpty()) {
            return defaultColor.getValue();
        }

        Optional<Attr> attrOptional = attrSet.getAttr(attrName);
        if (attrOptional == null || !attrOptional.isPresent()) {
            return defaultColor.getValue();
        }
        return attrOptional.get().getColorValue().getValue();
    }
}
